﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Mvc;

using Mvc.XForms.Controls.Settings;
using Mvc.XForms.Utilities;
using System.Web;

namespace Mvc.XForms.Controls {
	public class XFormRepeat<TParentContext, TContext> : XFormContextBase<TParentContext, TContext>, IRepeat<TContext> {
		private Expression<Func<TParentContext, IEnumerable<TContext>>> bind;
		private IEnumerable<TContext> items;
		private string itemBegin;
		private string itemEnd;
		private string templateID;

		public RepeatSettings<TContext> Settings { get; private set; }
		public Action<IRepeat<TContext>> ItemTemplateAction { get; set; }
		public string Tag { get; set; }
		public string ItemTag { get; set; }
		public TContext DefaultItem { get; set; }
		public string ItemTemplate { get; set; }

		public override XFormControlType ControlType {
			get { return XFormControlType.Repeat; }
		}

		public XFormRepeat(IContainerControl<TParentContext> parent, Expression<Func<TParentContext, IEnumerable<TContext>>> bind)
			: base(parent, bind.Body) {
			Settings = new RepeatSettings<TContext>(this);
			items = bind.Compile()(parent.ModelContext) as IEnumerable<TContext> ?? Activator.CreateInstance<List<TContext>>();
			CssClass.Add("repeat");
			this.bind = bind;
		}

		public override void Render() {
			ApplySettingsOrDefaults();

			var resp = XForm.HttpContext.Response;
			OutputRepeat(resp);
		}

		public virtual void ApplySettingsOrDefaults() {
			Label = Label ?? bind.Body.ExtractMember().CapitalizeSpace();
			Tag = Tag ?? "ul";
			ItemTag = ItemTag ?? "li";

			if (DefaultItem == null)
				DefaultItem = default(TContext) == null ? Activator.CreateInstance<TContext>() : default(TContext);
		}

		public virtual void OutputRepeat(HttpResponseBase resp) {
			var repeatBegin = XForm.Formatter.RepeatBegin(this);
			var repeatEnd = XForm.Formatter.RepeatEnd(this);
			itemBegin = XForm.Formatter.RepeatItemBegin(this);
			itemEnd = XForm.Formatter.RepeatItemEnd(this);

			if (IsInRepeatTemplate) {
				ItemTemplate = BuildScriptItemTemplate();
				SetChildAsInRepeatTemplate = false;
			}

			resp.Write(repeatBegin);
			RenderItems();
			resp.Write(repeatEnd);
		}

		private string BuildScriptItemTemplate() {
			// possibly need a smarter way to do this
			//var regexStr = string.Concat("< id=\"", ClientID)
			//var regex = new Regex(ClientID
			var template = GetTemplate();

			// Escape script quotes
			template = template
				.Replace("'", "''");

			return template.ToString();
		}

		private string GetTemplate() {
			var resp = XForm.HttpContext.Response;
			var capturer = new ResponseCapturer(resp);
			capturer.InitCapturing();

			// Render the template with the default item
			// **HACK**: how can we escape the template as a whole
			// without escaping the control ID's???
			var originalFullID = FullID;
			templateID = string.Concat(FullID, ExpressionHelper.IndexSeparator);
			FullID = templateID;
			RenderItem(DefaultItem);
			FullID = originalFullID;

			return capturer.ReadAndReset();
		}

		public virtual void RenderItems() {
			var originalFullID = FullID;
			items.ForEach((item, index) => {
				FullID = string.Concat(FullID, ExpressionHelper.IndexSeparator, index);
				RenderItem(item);
				FullID = originalFullID;
			});
		}

		public virtual void RenderItem(TContext item) {
			ModelContext = item;

			var resp = XForm.HttpContext.Response;
			OutputItem(resp);
		}

		public virtual void OutputItem(HttpResponseBase resp) {
			resp.Write(itemBegin);
			ItemTemplateAction(this);
			resp.Write(itemEnd);
		}

		public override object ToJson() {
			if (IsInRepeatTemplate) {
				var json = new {
					id = ID,
					type = (int)ControlType,
					acts = Actions.Select(act => act.ToJson()),
					cons = Controls.Select(con => con.ToJson()).Where(obj => obj != null),
					itemTemplate = ItemTemplate,
					templateID = templateID
				};
				return json;
			}

			return null;
		}
	}
}